package com.willpower.eureka.config;

import com.willpower.eureka.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: wen-yi;
 * @date: 2021/10/29 23:52;
 * @Description:
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserService userService;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    @Qualifier("jwtTokenStore")
    private TokenStore jwtTokenStore;
    /* 一般jwt令牌 不存储于redis耗时 耗资源 且不安全 oauth2令牌可以存储
    @Autowired
    @Qualifier("redisTokenStore")
    private TokenStore redisTokenStore;
    */
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Autowired
    private TokenEnhancer tokenEnhancer;
    @Autowired
    private DataSource dataSource;

    //密码模式
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //增强链
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> delegates = new ArrayList<>();
        delegates.add(tokenEnhancer);
        delegates.add(jwtAccessTokenConverter);
        tokenEnhancerChain.setTokenEnhancers(delegates);

        endpoints
                //自定义登录逻辑
                .userDetailsService(userService)
                //授权管理器
                .authenticationManager(authenticationManager)
                //令牌存储位置
                .tokenStore(jwtTokenStore)
                .accessTokenConverter(jwtAccessTokenConverter)
                //token增强链
                .tokenEnhancer(tokenEnhancerChain);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
        /*
                // 第一次需要进行插入 后面便不再需要 否则会报id冲突
                // ClientId
                .withClient("admin")
                // 密码
                .secret(passwordEncoder.encode("990716"))
                //访问令牌失效时间
                .accessTokenValiditySeconds(36000)
                //刷新令牌失效时间
                .refreshTokenValiditySeconds(184000)
                // 重定向地址 用于获取授权码
                .redirectUris("http://localhost:11002/login")
                //自动授权
                .autoApprove(true)
                // 授权范围
                .scopes("all")
                // 授权类型 :授权码模式 密码模式 刷新模式 客户端模式
                .authorizedGrantTypes("authorization_code","password","refresh_token");
        */
        //clients客户端 可以使用JDBC进行数据库配置 这里使用内存
        /*
        clients.inMemory()
                //clientId
                .withClient("admin")
                //client密码
                .secret(passwordEncoder.encode("990716"))
                //访问令牌失效时间
                .accessTokenValiditySeconds(36000)
                //刷新令牌失效时间
                .refreshTokenValiditySeconds(184000)
                //重定向地址，获取授权码
                .redirectUris("http://localhost:11002/login")
                //自动授权
                .autoApprove(true)
                //授权范围
                .scopes("all")
                //授权类型: 授权码模式 密码模式 加一个刷新令牌
                .authorizedGrantTypes("authorization_code","password","refresh_token");
         */
        // 获取授权码：http://localhost:11000/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://localhost:11002/login&scope=all
        // http://localhost:11002/error?code=yPx1WT
        // 获取到授权码后 使用postMan获取token 再访问资源
        // http://localhost:11000/oauth/token
        // Basic Auth : admin/990716
        // x-www-form-urlencoded: {"grant_type":"authorization_code","client_id":"admin","redirect_uri":"http://wwww.baidu.com","scope":"all","code":"yPx1WT"}
        // 或者
        // form-data: {"grant_type":"password","username":"admin","scope":"all","password":"990716"}
        //使用postMan进行测试
        /*
        {
            "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsaWtlIjoiYWoiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2MzU4MDc3NDgsImF1dGhvcml0aWVzIjpbImFkbWluIiwiUk9MRV9yb290Il0sImp0aSI6IjRlM2U0OWZmLWU1MDMtNDAyZC05ZjkxLTM4NDFmN2QzYThiMyIsImNsaWVudF9pZCI6ImFkbWluIn0.KemvxHNcf_IL0rHJ1kMWDoV7tBwCrsEysEb8be2ZhyE",
            "token_type": "bearer",
            "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsaWtlIjoiYWoiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiI0ZTNlNDlmZi1lNTAzLTQwMmQtOWY5MS0zODQxZjdkM2E4YjMiLCJleHAiOjE2MzU5NTU3NDgsImF1dGhvcml0aWVzIjpbImFkbWluIiwiUk9MRV9yb290Il0sImp0aSI6IjMxODU1ZWRmLWU5MDQtNGUzOC1iMzhmLWQzNjRlNDg4MGYwYiIsImNsaWVudF9pZCI6ImFkbWluIn0.VUhAn6hc2wWeeQDQ_wZKuVLUrIH3cme_Ifo2XGZfQzg",
            "expires_in": 35999,
            "scope": "all",
            "like": "aj",
            "jti": "4e3e49ff-e503-402d-9f91-3841f7d3a8b3"
        }
        */
        // 访问资源 http://localhost:11000/user/getCurrentUser
        // Bearer Token : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsaWtlIjoiYWoiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2MzU4MDc3NDgsImF1dGhvcml0aWVzIjpbImFkbWluIiwiUk9MRV9yb290Il0sImp0aSI6IjRlM2U0OWZmLWU1MDMtNDAyZC05ZjkxLTM4NDFmN2QzYThiMyIsImNsaWVudF9pZCI6ImFkbWluIn0.KemvxHNcf_IL0rHJ1kMWDoV7tBwCrsEysEb8be2ZhyE"
        // 上面的请求获取的信息并不完整
        // 访问资源 http://localhost:11000/user/getAllCurrentUser
        // Header | Authorization : "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsaWtlIjoiYWoiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2MzU4MTAyMjgsImF1dGhvcml0aWVzIjpbImFkbWluIiwiUk9MRV9yb290Il0sImp0aSI6IjIyMTkxOTY2LTk2MjAtNGRjMC04N2FhLWFhY2Y5ZjIxMGExYSIsImNsaWVudF9pZCI6ImFkbWluIn0.VwrP4HssiVGZKnGIONUv20Ih4UrWoS_e4oICxC4vbQQ"
        // 刷新令牌 http://localhost:11000/oauth/token
        // Basic Auth : admin/990716
        // form-data: {"grant_type":"refresh_token","username":"admin","scope":"all","password":"990716","refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsaWtlIjoiYWoiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiI5MjIxNmE4ZC1hN2YzLTRlNDUtYjI3Mi1mNWQzNGQ1OTEzOTQiLCJleHAiOjE2MzU5NTg5NzUsImF1dGhvcml0aWVzIjpbImFkbWluIiwiUk9MRV9yb290Il0sImp0aSI6Ijc4MTQ2Zjk0LTBiOGMtNGQ2My1iNGRjLTFhZTk5MjU4MjdjOCIsImNsaWVudF9pZCI6ImFkbWluIn0.H8J6kAnEMrRdcafOYS9jJk89CFDFemDXr0KZg7UFX3E"}

    }

    /**
     *
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // 单点登录使用
        // security.tokenKeyAccess("isAuthenticated()");

        // 对获取Token的请求不再拦截
        security
                .tokenKeyAccess("permitAll()")
                // 验证获取Token的验证信息
                .checkTokenAccess("isAuthenticated()")
                //这个如果配置支持allowFormAuthenticationForClients的，且对/oauth/token请求的参数中有client_id和client-secret的会走ClientCredentialsTokenEndpointFilter来保护
                //如果没有支持allowFormAuthenticationForClients或者有支持但对/oauth/token请求的参数中没有client_id和client_secret的，走basic认证保护
                .allowFormAuthenticationForClients();
    }
}
